home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume23 / flex2.3 / part08 < prev    next >
Encoding:
Internet Message Format  |  1990-10-10  |  51.3 KB

  1. Subject:  v23i044:  Flex, a fast lex replacement, Part08/10
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: ca66ccd4 e23a0f71 33039016 677e8981
  5.  
  6. Submitted-by: Vern Paxson <vern@cs.cornell.edu>
  7. Posting-number: Volume 23, Issue 44
  8. Archive-name: flex2.3/part08
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # Contents:  flexdoc.1.02 misc.c nfa.c
  17. # Wrapped by rsalz@litchi.bbn.com on Wed Oct 10 13:24:04 1990
  18. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  19. echo If this archive is complete, you will see the following message:
  20. echo '          "shar: End of archive 8 (of 10)."'
  21. if test -f 'flexdoc.1.02' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'flexdoc.1.02'\"
  23. else
  24.   echo shar: Extracting \"'flexdoc.1.02'\" \(15514 characters\)
  25.   sed "s/^X//" >'flexdoc.1.02' <<'END_OF_FILE'
  26. XAnother area where the user can increase a scanner's performance
  27. X(and one that's easier to implement) arises from the fact that
  28. Xthe longer the tokens matched, the faster the scanner will run.
  29. XThis is because with long tokens the processing of most input
  30. Xcharacters takes place in the (short) inner scanning loop, and
  31. Xdoes not often have to go through the additional work of setting up
  32. Xthe scanning environment (e.g.,
  33. X.B yytext)
  34. Xfor the action.  Recall the scanner for C comments:
  35. X.nf
  36. X
  37. X    %x comment
  38. X    %%
  39. X            int line_num = 1;
  40. X
  41. X    "/*"         BEGIN(comment);
  42. X
  43. X    <comment>[^*\\n]*
  44. X    <comment>"*"+[^*/\\n]*
  45. X    <comment>\\n             ++line_num;
  46. X    <comment>"*"+"/"        BEGIN(INITIAL);
  47. X
  48. X.fi
  49. XThis could be sped up by writing it as:
  50. X.nf
  51. X
  52. X    %x comment
  53. X    %%
  54. X            int line_num = 1;
  55. X
  56. X    "/*"         BEGIN(comment);
  57. X
  58. X    <comment>[^*\\n]*
  59. X    <comment>[^*\\n]*\\n      ++line_num;
  60. X    <comment>"*"+[^*/\\n]*
  61. X    <comment>"*"+[^*/\\n]*\\n ++line_num;
  62. X    <comment>"*"+"/"        BEGIN(INITIAL);
  63. X
  64. X.fi
  65. XNow instead of each newline requiring the processing of another
  66. Xaction, recognizing the newlines is "distributed" over the other rules
  67. Xto keep the matched text as long as possible.  Note that
  68. X.I adding
  69. Xrules does
  70. X.I not
  71. Xslow down the scanner!  The speed of the scanner is independent
  72. Xof the number of rules or (modulo the considerations given at the
  73. Xbeginning of this section) how complicated the rules are with
  74. Xregard to operators such as '*' and '|'.
  75. X.LP
  76. XA final example in speeding up a scanner: suppose you want to scan
  77. Xthrough a file containing identifiers and keywords, one per line
  78. Xand with no other extraneous characters, and recognize all the
  79. Xkeywords.  A natural first approach is:
  80. X.nf
  81. X
  82. X    %%
  83. X    asm      |
  84. X    auto     |
  85. X    break    |
  86. X    ... etc ...
  87. X    volatile |
  88. X    while    /* it's a keyword */
  89. X
  90. X    .|\\n     /* it's not a keyword */
  91. X
  92. X.fi
  93. XTo eliminate the back-tracking, introduce a catch-all rule:
  94. X.nf
  95. X
  96. X    %%
  97. X    asm      |
  98. X    auto     |
  99. X    break    |
  100. X    ... etc ...
  101. X    volatile |
  102. X    while    /* it's a keyword */
  103. X
  104. X    [a-z]+   |
  105. X    .|\\n     /* it's not a keyword */
  106. X
  107. X.fi
  108. XNow, if it's guaranteed that there's exactly one word per line,
  109. Xthen we can reduce the total number of matches by a half by
  110. Xmerging in the recognition of newlines with that of the other
  111. Xtokens:
  112. X.nf
  113. X
  114. X    %%
  115. X    asm\\n    |
  116. X    auto\\n   |
  117. X    break\\n  |
  118. X    ... etc ...
  119. X    volatile\\n |
  120. X    while\\n  /* it's a keyword */
  121. X
  122. X    [a-z]+\\n |
  123. X    .|\\n     /* it's not a keyword */
  124. X
  125. X.fi
  126. XOne has to be careful here, as we have now reintroduced backtracking
  127. Xinto the scanner.  In particular, while
  128. X.I we
  129. Xknow that there will never be any characters in the input stream
  130. Xother than letters or newlines,
  131. X.I flex
  132. Xcan't figure this out, and it will plan for possibly needing backtracking
  133. Xwhen it has scanned a token like "auto" and then the next character
  134. Xis something other than a newline or a letter.  Previously it would
  135. Xthen just match the "auto" rule and be done, but now it has no "auto"
  136. Xrule, only a "auto\\n" rule.  To eliminate the possibility of backtracking,
  137. Xwe could either duplicate all rules but without final newlines, or,
  138. Xsince we never expect to encounter such an input and therefore don't
  139. Xhow it's classified, we can introduce one more catch-all rule, this
  140. Xone which doesn't include a newline:
  141. X.nf
  142. X
  143. X    %%
  144. X    asm\\n    |
  145. X    auto\\n   |
  146. X    break\\n  |
  147. X    ... etc ...
  148. X    volatile\\n |
  149. X    while\\n  /* it's a keyword */
  150. X
  151. X    [a-z]+\\n |
  152. X    [a-z]+   |
  153. X    .|\\n     /* it's not a keyword */
  154. X
  155. X.fi
  156. XCompiled with
  157. X.B -Cf,
  158. Xthis is about as fast as one can get a
  159. X.I flex 
  160. Xscanner to go for this particular problem.
  161. X.LP
  162. XA final note:
  163. X.I flex
  164. Xis slow when matching NUL's, particularly when a token contains
  165. Xmultiple NUL's.
  166. XIt's best to write rules which match
  167. X.I short
  168. Xamounts of text if it's anticipated that the text will often include NUL's.
  169. X.SH INCOMPATIBILITIES WITH LEX AND POSIX
  170. X.I flex
  171. Xis a rewrite of the Unix
  172. X.I lex
  173. Xtool (the two implementations do not share any code, though),
  174. Xwith some extensions and incompatibilities, both of which
  175. Xare of concern to those who wish to write scanners acceptable
  176. Xto either implementation.  At present, the POSIX
  177. X.I lex
  178. Xdraft is
  179. Xvery close to the original
  180. X.I lex
  181. Ximplementation, so some of these
  182. Xincompatibilities are also in conflict with the POSIX draft.  But
  183. Xthe intent is that except as noted below,
  184. X.I flex
  185. Xas it presently stands will
  186. Xultimately be POSIX conformant (i.e., that those areas of conflict with
  187. Xthe POSIX draft will be resolved in
  188. X.I flex's
  189. Xfavor).  Please bear in
  190. Xmind that all the comments which follow are with regard to the POSIX
  191. X.I draft
  192. Xstandard of Summer 1989, and not the final document (or subsequent
  193. Xdrafts); they are included so
  194. X.I flex
  195. Xusers can be aware of the standardization issues and those areas where
  196. X.I flex
  197. Xmay in the near future undergo changes incompatible with
  198. Xits current definition.
  199. X.LP
  200. X.I flex
  201. Xis fully compatible with
  202. X.I lex
  203. Xwith the following exceptions:
  204. X.IP -
  205. XThe undocumented
  206. X.I lex
  207. Xscanner internal variable
  208. X.B yylineno
  209. Xis not supported.  It is difficult to support this option efficiently,
  210. Xsince it requires examining every character scanned and reexamining
  211. Xthe characters when the scanner backs up.
  212. XThings get more complicated when the end of buffer or file is reached or a
  213. XNUL is scanned (since the scan must then be restarted with the proper line
  214. Xnumber count), or the user uses the yyless(), unput(), or REJECT actions,
  215. Xor the multiple input buffer functions.
  216. X.IP
  217. XThe fix is to add rules which, upon seeing a newline, increment
  218. Xyylineno.  This is usually an easy process, though it can be a drag if some
  219. Xof the patterns can match multiple newlines along with other characters.
  220. X.IP
  221. Xyylineno is not part of the POSIX draft.
  222. X.IP -
  223. XThe
  224. X.B input()
  225. Xroutine is not redefinable, though it may be called to read characters
  226. Xfollowing whatever has been matched by a rule.  If
  227. X.B input()
  228. Xencounters an end-of-file the normal
  229. X.B yywrap()
  230. Xprocessing is done.  A ``real'' end-of-file is returned by
  231. X.B input()
  232. Xas
  233. X.I EOF.
  234. X.IP
  235. XInput is instead controlled by redefining the
  236. X.B YY_INPUT
  237. Xmacro.
  238. X.IP
  239. XThe
  240. X.I flex
  241. Xrestriction that
  242. X.B input()
  243. Xcannot be redefined is in accordance with the POSIX draft, but
  244. X.B YY_INPUT
  245. Xhas not yet been accepted into the draft (and probably won't; it looks
  246. Xlike the draft will simply not specify any way of controlling the
  247. Xscanner's input other than by making an initial assignment to
  248. X.I yyin).
  249. X.IP -
  250. X.I flex
  251. Xscanners do not use stdio for input.  Because of this, when writing an
  252. Xinteractive scanner one must explicitly call fflush() on the
  253. Xstream associated with the terminal after writing out a prompt.
  254. XWith
  255. X.I lex
  256. Xsuch writes are automatically flushed since
  257. X.I lex
  258. Xscanners use
  259. X.B getchar()
  260. Xfor their input.  Also, when writing interactive scanners with
  261. X.I flex,
  262. Xthe
  263. X.B -I
  264. Xflag must be used.
  265. X.IP -
  266. X.I flex
  267. Xscanners are not as reentrant as
  268. X.I lex
  269. Xscanners.  In particular, if you have an interactive scanner and
  270. Xan interrupt handler which long-jumps out of the scanner, and
  271. Xthe scanner is subsequently called again, you may get the following
  272. Xmessage:
  273. X.nf
  274. X
  275. X    fatal flex scanner internal error--end of buffer missed
  276. X
  277. X.fi
  278. XTo reenter the scanner, first use
  279. X.nf
  280. X
  281. X    yyrestart( yyin );
  282. X
  283. X.fi
  284. X.IP -
  285. X.B output()
  286. Xis not supported.
  287. XOutput from the
  288. X.B ECHO
  289. Xmacro is done to the file-pointer
  290. X.I yyout
  291. X(default
  292. X.I stdout).
  293. X.IP
  294. XThe POSIX draft mentions that an
  295. X.B output()
  296. Xroutine exists but currently gives no details as to what it does.
  297. X.IP -
  298. X.I lex
  299. Xdoes not support exclusive start conditions (%x), though they
  300. Xare in the current POSIX draft.
  301. X.IP -
  302. XWhen definitions are expanded,
  303. X.I flex
  304. Xencloses them in parentheses.
  305. XWith lex, the following:
  306. X.nf
  307. X
  308. X    NAME    [A-Z][A-Z0-9]*
  309. X    %%
  310. X    foo{NAME}?      printf( "Found it\\n" );
  311. X    %%
  312. X
  313. X.fi
  314. Xwill not match the string "foo" because when the macro
  315. Xis expanded the rule is equivalent to "foo[A-Z][A-Z0-9]*?"
  316. Xand the precedence is such that the '?' is associated with
  317. X"[A-Z0-9]*".  With
  318. X.I flex,
  319. Xthe rule will be expanded to
  320. X"foo([A-Z][A-Z0-9]*)?" and so the string "foo" will match.
  321. XNote that because of this, the
  322. X.B ^, $, <s>, /,
  323. Xand
  324. X.B <<EOF>>
  325. Xoperators cannot be used in a
  326. X.I flex
  327. Xdefinition.
  328. X.IP
  329. XThe POSIX draft interpretation is the same as
  330. X.I flex's.
  331. X.IP -
  332. XTo specify a character class which matches anything but a left bracket (']'),
  333. Xin
  334. X.I lex
  335. Xone can use "[^]]" but with
  336. X.I flex
  337. Xone must use "[^\\]]".  The latter works with
  338. X.I lex,
  339. Xtoo.
  340. X.IP -
  341. XThe
  342. X.I lex
  343. X.B %r
  344. X(generate a Ratfor scanner) option is not supported.  It is not part
  345. Xof the POSIX draft.
  346. X.IP -
  347. XIf you are providing your own yywrap() routine, you must include a
  348. X"#undef yywrap" in the definitions section (section 1).  Note that
  349. Xthe "#undef" will have to be enclosed in %{}'s.
  350. X.IP
  351. XThe POSIX draft
  352. Xspecifies that yywrap() is a function and this is very unlikely to change; so
  353. X.I flex users are warned
  354. Xthat
  355. X.B yywrap()
  356. Xis likely to be changed to a function in the near future.
  357. X.IP -
  358. XAfter a call to
  359. X.B unput(),
  360. X.I yytext
  361. Xand
  362. X.I yyleng
  363. Xare undefined until the next token is matched.  This is not the case with
  364. X.I lex
  365. Xor the present POSIX draft.
  366. X.IP -
  367. XThe precedence of the
  368. X.B {}
  369. X(numeric range) operator is different.
  370. X.I lex
  371. Xinterprets "abc{1,3}" as "match one, two, or
  372. Xthree occurrences of 'abc'", whereas
  373. X.I flex
  374. Xinterprets it as "match 'ab'
  375. Xfollowed by one, two, or three occurrences of 'c'".  The latter is
  376. Xin agreement with the current POSIX draft.
  377. X.IP -
  378. XThe precedence of the
  379. X.B ^
  380. Xoperator is different.
  381. X.I lex
  382. Xinterprets "^foo|bar" as "match either 'foo' at the beginning of a line,
  383. Xor 'bar' anywhere", whereas
  384. X.I flex
  385. Xinterprets it as "match either 'foo' or 'bar' if they come at the beginning
  386. Xof a line".  The latter is in agreement with the current POSIX draft.
  387. X.IP -
  388. XTo refer to yytext outside of the scanner source file,
  389. Xthe correct definition with
  390. X.I flex
  391. Xis "extern char *yytext" rather than "extern char yytext[]".
  392. XThis is contrary to the current POSIX draft but a point on which
  393. X.I flex
  394. Xwill not be changing, as the array representation entails a
  395. Xserious performance penalty.  It is hoped that the POSIX draft will
  396. Xbe emended to support the
  397. X.I flex
  398. Xvariety of declaration (as this is a fairly painless change to
  399. Xrequire of
  400. X.I lex
  401. Xusers).
  402. X.IP -
  403. X.I yyin
  404. Xis
  405. X.I initialized
  406. Xby
  407. X.I lex
  408. Xto be
  409. X.I stdin;
  410. X.I flex,
  411. Xon the other hand,
  412. Xinitializes
  413. X.I yyin
  414. Xto NULL
  415. Xand then
  416. X.I assigns
  417. Xit to
  418. X.I stdin
  419. Xthe first time the scanner is called, providing
  420. X.I yyin
  421. Xhas not already been assigned to a non-NULL value.  The difference is
  422. Xsubtle, but the net effect is that with
  423. X.I flex
  424. Xscanners,
  425. X.I yyin
  426. Xdoes not have a valid value until the scanner has been called.
  427. X.IP -
  428. XThe special table-size declarations such as
  429. X.B %a
  430. Xsupported by
  431. X.I lex
  432. Xare not required by
  433. X.I flex
  434. Xscanners;
  435. X.I flex
  436. Xignores them.
  437. X.IP -
  438. XThe name
  439. X.bd
  440. XFLEX_SCANNER
  441. Xis #define'd so scanners may be written for use with either
  442. X.I flex
  443. Xor
  444. X.I lex.
  445. X.LP
  446. XThe following
  447. X.I flex
  448. Xfeatures are not included in
  449. X.I lex
  450. Xor the POSIX draft standard:
  451. X.nf
  452. X
  453. X    yyterminate()
  454. X    <<EOF>>
  455. X    YY_DECL
  456. X    #line directives
  457. X    %{}'s around actions
  458. X    yyrestart()
  459. X    comments beginning with '#' (deprecated)
  460. X    multiple actions on a line
  461. X
  462. X.fi
  463. XThis last feature refers to the fact that with
  464. X.I flex
  465. Xyou can put multiple actions on the same line, separated with
  466. Xsemi-colons, while with
  467. X.I lex,
  468. Xthe following
  469. X.nf
  470. X
  471. X    foo    handle_foo(); ++num_foos_seen;
  472. X
  473. X.fi
  474. Xis (rather surprisingly) truncated to
  475. X.nf
  476. X
  477. X    foo    handle_foo();
  478. X
  479. X.fi
  480. X.I flex
  481. Xdoes not truncate the action.  Actions that are not enclosed in
  482. Xbraces are simply terminated at the end of the line.
  483. X.SH DIAGNOSTICS
  484. X.I reject_used_but_not_detected undefined
  485. Xor
  486. X.I yymore_used_but_not_detected undefined -
  487. XThese errors can occur at compile time.  They indicate that the
  488. Xscanner uses
  489. X.B REJECT
  490. Xor
  491. X.B yymore()
  492. Xbut that
  493. X.I flex
  494. Xfailed to notice the fact, meaning that
  495. X.I flex
  496. Xscanned the first two sections looking for occurrences of these actions
  497. Xand failed to find any, but somehow you snuck some in (via a #include
  498. Xfile, for example).  Make an explicit reference to the action in your
  499. X.I flex
  500. Xinput file.  (Note that previously
  501. X.I flex
  502. Xsupported a
  503. X.B %used/%unused
  504. Xmechanism for dealing with this problem; this feature is still supported
  505. Xbut now deprecated, and will go away soon unless the author hears from
  506. Xpeople who can argue compellingly that they need it.)
  507. X.LP
  508. X.I flex scanner jammed -
  509. Xa scanner compiled with
  510. X.B -s
  511. Xhas encountered an input string which wasn't matched by
  512. Xany of its rules.
  513. X.LP
  514. X.I flex input buffer overflowed -
  515. Xa scanner rule matched a string long enough to overflow the
  516. Xscanner's internal input buffer (16K bytes by default - controlled by
  517. X.B YY_BUF_SIZE
  518. Xin "flex.skel".  Note that to redefine this macro, you must first
  519. X.B #undefine
  520. Xit).
  521. X.LP
  522. X.I scanner requires -8 flag -
  523. XYour scanner specification includes recognizing 8-bit characters and
  524. Xyou did not specify the -8 flag (and your site has not installed flex
  525. Xwith -8 as the default).
  526. X.LP
  527. X.I
  528. Xfatal flex scanner internal error--end of buffer missed -
  529. XThis can occur in an scanner which is reentered after a long-jump
  530. Xhas jumped out (or over) the scanner's activation frame.  Before
  531. Xreentering the scanner, use:
  532. X.nf
  533. X
  534. X    yyrestart( yyin );
  535. X
  536. X.fi
  537. X.LP
  538. X.I too many %t classes! -
  539. XYou managed to put every single character into its own %t class.
  540. X.I flex
  541. Xrequires that at least one of the classes share characters.
  542. X.SH DEFICIENCIES / BUGS
  543. XSee flex(1).
  544. X.SH "SEE ALSO"
  545. X.LP
  546. Xflex(1), lex(1), yacc(1), sed(1), awk(1).
  547. X.LP
  548. XM. E. Lesk and E. Schmidt,
  549. X.I LEX - Lexical Analyzer Generator
  550. X.SH AUTHOR
  551. XVern Paxson, with the help of many ideas and much inspiration from
  552. XVan Jacobson.  Original version by Jef Poskanzer.  The fast table
  553. Xrepresentation is a partial implementation of a design done by Van
  554. XJacobson.  The implementation was done by Kevin Gong and Vern Paxson.
  555. X.LP
  556. XThanks to the many
  557. X.I flex
  558. Xbeta-testers, feedbackers, and contributors, especially Casey
  559. XLeedom, benson@odi.com, Keith Bostic,
  560. XFrederic Brehm, Nick Christopher, Jason Coughlin,
  561. XScott David Daniels, Leo Eskin,
  562. XChris Faylor, Eric Goldman, Eric
  563. XHughes, Jeffrey R. Jones, Kevin B. Kenny, Ronald Lamprecht,
  564. XGreg Lee, Craig Leres, Mohamed el Lozy, Jim Meyering, Marc Nozell, Esmond Pitt,
  565. XJef Poskanzer, Jim Roskind,
  566. XDave Tallman, Frank Whaley, Ken Yap, and those whose names
  567. Xhave slipped my marginal mail-archiving skills but whose contributions
  568. Xare appreciated all the same.
  569. X.LP
  570. XThanks to Keith Bostic, John Gilmore, Craig Leres, Bob
  571. XMulcahy, Rich Salz, and Richard Stallman for help with various distribution
  572. Xheadaches.
  573. X.LP
  574. XThanks to Esmond Pitt and Earle Horton for 8-bit character support;
  575. Xto Benson Margulies and Fred
  576. XBurke for C++ support; to Ove Ewerlid for the basics of support for
  577. XNUL's; and to Eric Hughes for the basics of support for multiple buffers.
  578. X.LP
  579. XWork is being done on extending
  580. X.I flex
  581. Xto generate scanners in which the
  582. Xstate machine is directly represented in C code rather than tables.
  583. XThese scanners may well be substantially faster than those generated
  584. Xusing -f or -F.  If you are working in this area and are interested
  585. Xin comparing notes and seeing whether redundant work can be avoided,
  586. Xcontact Ove Ewerlid (ewerlid@mizar.DoCS.UU.SE).
  587. X.LP
  588. XThis work was primarily done when I was at the Real Time Systems Group
  589. Xat the Lawrence Berkeley Laboratory in Berkeley, CA.  Many thanks to all there
  590. Xfor the support I received.
  591. X.LP
  592. XSend comments to:
  593. X.nf
  594. X
  595. X     Vern Paxson
  596. X     Computer Science Department
  597. X     4126 Upson Hall
  598. X     Cornell University
  599. X     Ithaca, NY 14853-7501
  600. X
  601. X     vern@cs.cornell.edu
  602. X     decvax!cornell!vern
  603. X
  604. X.fi
  605. END_OF_FILE
  606.   if test 15514 -ne `wc -c <'flexdoc.1.02'`; then
  607.     echo shar: \"'flexdoc.1.02'\" unpacked with wrong size!
  608.   fi
  609.   # end of 'flexdoc.1.02'
  610. fi
  611. if test -f 'misc.c' -a "${1}" != "-c" ; then 
  612.   echo shar: Will not clobber existing file \"'misc.c'\"
  613. else
  614.   echo shar: Extracting \"'misc.c'\" \(14912 characters\)
  615.   sed "s/^X//" >'misc.c' <<'END_OF_FILE'
  616. X/* misc - miscellaneous flex routines */
  617. X
  618. X/*-
  619. X * Copyright (c) 1990 The Regents of the University of California.
  620. X * All rights reserved.
  621. X *
  622. X * This code is derived from software contributed to Berkeley by
  623. X * Vern Paxson.
  624. X * 
  625. X * The United States Government has rights in this work pursuant
  626. X * to contract no. DE-AC03-76SF00098 between the United States
  627. X * Department of Energy and the University of California.
  628. X *
  629. X * Redistribution and use in source and binary forms are permitted provided
  630. X * that: (1) source distributions retain this entire copyright notice and
  631. X * comment, and (2) distributions including binaries display the following
  632. X * acknowledgement:  ``This product includes software developed by the
  633. X * University of California, Berkeley and its contributors'' in the
  634. X * documentation or other materials provided with the distribution and in
  635. X * all advertising materials mentioning features or use of this software.
  636. X * Neither the name of the University nor the names of its contributors may
  637. X * be used to endorse or promote products derived from this software without
  638. X * specific prior written permission.
  639. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  640. X * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  641. X * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  642. X */
  643. X
  644. X#ifndef lint
  645. Xstatic char rcsid[] =
  646. X    "@(#) $Header: /usr/fsys/odin/a/vern/flex/RCS/misc.c,v 2.9 90/08/14 00:10:24 vern Exp $ (LBL)";
  647. X#endif
  648. X
  649. X#include <ctype.h>
  650. X#include "flexdef.h"
  651. X
  652. X
  653. X/* ANSI C does not guarantee that isascii() is defined */
  654. X#ifndef isascii
  655. X#define isascii(c) ((c) <= 0177)
  656. X#endif
  657. X
  658. X
  659. X
  660. X/* declare functions that have forward references */
  661. X
  662. Xvoid dataflush PROTO(());
  663. Xint otoi PROTO((Char []));
  664. X
  665. X
  666. X/* action_out - write the actions from the temporary file to lex.yy.c
  667. X *
  668. X * synopsis
  669. X *     action_out();
  670. X *
  671. X *     Copies the action file up to %% (or end-of-file) to lex.yy.c
  672. X */
  673. X
  674. Xvoid action_out()
  675. X
  676. X    {
  677. X    char buf[MAXLINE];
  678. X
  679. X    while ( fgets( buf, MAXLINE, temp_action_file ) != NULL )
  680. X    if ( buf[0] == '%' && buf[1] == '%' )
  681. X        break;
  682. X    else
  683. X        fputs( buf, stdout );
  684. X    }
  685. X
  686. X
  687. X/* allocate_array - allocate memory for an integer array of the given size */
  688. X
  689. Xvoid *allocate_array( size, element_size )
  690. Xint size, element_size;
  691. X
  692. X    {
  693. X    register void *mem;
  694. X
  695. X    /* on 16-bit int machines (e.g., 80286) we might be trying to
  696. X     * allocate more than a signed int can hold, and that won't
  697. X     * work.  Cheap test:
  698. X     */
  699. X    if ( element_size * size <= 0 )
  700. X        flexfatal( "request for < 1 byte in allocate_array()" );
  701. X
  702. X    mem = (void *) malloc( (unsigned) (element_size * size) );
  703. X
  704. X    if ( mem == NULL )
  705. X    flexfatal( "memory allocation failed in allocate_array()" );
  706. X
  707. X    return ( mem );
  708. X    }
  709. X
  710. X
  711. X/* all_lower - true if a string is all lower-case
  712. X *
  713. X * synopsis:
  714. X *    Char *str;
  715. X *    int all_lower();
  716. X *    true/false = all_lower( str );
  717. X */
  718. X
  719. Xint all_lower( str )
  720. Xregister Char *str;
  721. X
  722. X    {
  723. X    while ( *str )
  724. X    {
  725. X    if ( ! isascii( *str ) || ! islower( *str ) )
  726. X        return ( 0 );
  727. X    ++str;
  728. X    }
  729. X
  730. X    return ( 1 );
  731. X    }
  732. X
  733. X
  734. X/* all_upper - true if a string is all upper-case
  735. X *
  736. X * synopsis:
  737. X *    Char *str;
  738. X *    int all_upper();
  739. X *    true/false = all_upper( str );
  740. X */
  741. X
  742. Xint all_upper( str )
  743. Xregister Char *str;
  744. X
  745. X    {
  746. X    while ( *str )
  747. X    {
  748. X    if ( ! isascii( *str ) || ! isupper( (char) *str ) )
  749. X        return ( 0 );
  750. X    ++str;
  751. X    }
  752. X
  753. X    return ( 1 );
  754. X    }
  755. X
  756. X
  757. X/* bubble - bubble sort an integer array in increasing order
  758. X *
  759. X * synopsis
  760. X *   int v[n], n;
  761. X *   bubble( v, n );
  762. X *
  763. X * description
  764. X *   sorts the first n elements of array v and replaces them in
  765. X *   increasing order.
  766. X *
  767. X * passed
  768. X *   v - the array to be sorted
  769. X *   n - the number of elements of 'v' to be sorted */
  770. X
  771. Xvoid bubble( v, n )
  772. Xint v[], n;
  773. X
  774. X    {
  775. X    register int i, j, k;
  776. X
  777. X    for ( i = n; i > 1; --i )
  778. X    for ( j = 1; j < i; ++j )
  779. X        if ( v[j] > v[j + 1] )    /* compare */
  780. X        {
  781. X        k = v[j];    /* exchange */
  782. X        v[j] = v[j + 1];
  783. X        v[j + 1] = k;
  784. X        }
  785. X    }
  786. X
  787. X
  788. X/* clower - replace upper-case letter to lower-case
  789. X *
  790. X * synopsis:
  791. X *    Char clower();
  792. X *    int c;
  793. X *    c = clower( c );
  794. X */
  795. X
  796. XChar clower( c )
  797. Xregister int c;
  798. X
  799. X    {
  800. X    return ( (isascii( c ) && isupper( c )) ? tolower( c ) : c );
  801. X    }
  802. X
  803. X
  804. X/* copy_string - returns a dynamically allocated copy of a string
  805. X *
  806. X * synopsis
  807. X *    char *str, *copy, *copy_string();
  808. X *    copy = copy_string( str );
  809. X */
  810. X
  811. Xchar *copy_string( str )
  812. Xregister char *str;
  813. X
  814. X    {
  815. X    register char *c;
  816. X    char *copy;
  817. X
  818. X    /* find length */
  819. X    for ( c = str; *c; ++c )
  820. X    ;
  821. X
  822. X    copy = malloc( (unsigned) ((c - str + 1) * sizeof( char )) );
  823. X
  824. X    if ( copy == NULL )
  825. X    flexfatal( "dynamic memory failure in copy_string()" );
  826. X
  827. X    for ( c = copy; (*c++ = *str++); )
  828. X    ;
  829. X
  830. X    return ( copy );
  831. X    }
  832. X
  833. X
  834. X/* copy_unsigned_string -
  835. X *    returns a dynamically allocated copy of a (potentially) unsigned string
  836. X *
  837. X * synopsis
  838. X *    Char *str, *copy, *copy_unsigned_string();
  839. X *    copy = copy_unsigned_string( str );
  840. X */
  841. X
  842. XChar *copy_unsigned_string( str )
  843. Xregister Char *str;
  844. X
  845. X    {
  846. X    register Char *c;
  847. X    Char *copy;
  848. X
  849. X    /* find length */
  850. X    for ( c = str; *c; ++c )
  851. X    ;
  852. X
  853. X    copy = (Char *) malloc( (unsigned) ((c - str + 1) * sizeof( Char )) );
  854. X
  855. X    if ( copy == NULL )
  856. X    flexfatal( "dynamic memory failure in copy_unsigned_string()" );
  857. X
  858. X    for ( c = copy; (*c++ = *str++); )
  859. X    ;
  860. X
  861. X    return ( copy );
  862. X    }
  863. X
  864. X
  865. X/* cshell - shell sort a character array in increasing order
  866. X *
  867. X * synopsis
  868. X *
  869. X *   Char v[n];
  870. X *   int n, special_case_0;
  871. X *   cshell( v, n, special_case_0 );
  872. X *
  873. X * description
  874. X *   does a shell sort of the first n elements of array v.
  875. X *   If special_case_0 is true, then any element equal to 0
  876. X *   is instead assumed to have infinite weight.
  877. X *
  878. X * passed
  879. X *   v - array to be sorted
  880. X *   n - number of elements of v to be sorted
  881. X */
  882. X
  883. Xvoid cshell( v, n, special_case_0 )
  884. XChar v[];
  885. Xint n, special_case_0;
  886. X
  887. X    {
  888. X    int gap, i, j, jg;
  889. X    Char k;
  890. X
  891. X    for ( gap = n / 2; gap > 0; gap = gap / 2 )
  892. X    for ( i = gap; i < n; ++i )
  893. X        for ( j = i - gap; j >= 0; j = j - gap )
  894. X        {
  895. X        jg = j + gap;
  896. X
  897. X        if ( special_case_0 )
  898. X            {
  899. X            if ( v[jg] == 0 )
  900. X            break;
  901. X
  902. X            else if ( v[j] != 0 && v[j] <= v[jg] )
  903. X            break;
  904. X            }
  905. X
  906. X        else if ( v[j] <= v[jg] )
  907. X            break;
  908. X
  909. X        k = v[j];
  910. X        v[j] = v[jg];
  911. X        v[jg] = k;
  912. X        }
  913. X    }
  914. X
  915. X
  916. X/* dataend - finish up a block of data declarations
  917. X *
  918. X * synopsis
  919. X *    dataend();
  920. X */
  921. X
  922. Xvoid dataend()
  923. X
  924. X    {
  925. X    if ( datapos > 0 )
  926. X    dataflush();
  927. X
  928. X    /* add terminator for initialization */
  929. X    puts( "    } ;\n" );
  930. X
  931. X    dataline = 0;
  932. X    datapos = 0;
  933. X    }
  934. X
  935. X
  936. X
  937. X/* dataflush - flush generated data statements
  938. X *
  939. X * synopsis
  940. X *    dataflush();
  941. X */
  942. X
  943. Xvoid dataflush()
  944. X
  945. X    {
  946. X    putchar( '\n' );
  947. X
  948. X    if ( ++dataline >= NUMDATALINES )
  949. X    {
  950. X    /* put out a blank line so that the table is grouped into
  951. X     * large blocks that enable the user to find elements easily
  952. X     */
  953. X    putchar( '\n' );
  954. X    dataline = 0;
  955. X    }
  956. X
  957. X    /* reset the number of characters written on the current line */
  958. X    datapos = 0;
  959. X    }
  960. X
  961. X
  962. X/* flexerror - report an error message and terminate
  963. X *
  964. X * synopsis
  965. X *    char msg[];
  966. X *    flexerror( msg );
  967. X */
  968. X
  969. Xvoid flexerror( msg )
  970. Xchar msg[];
  971. X
  972. X    {
  973. X    fprintf( stderr, "%s: %s\n", program_name, msg );
  974. X
  975. X    flexend( 1 );
  976. X    }
  977. X
  978. X
  979. X/* flexfatal - report a fatal error message and terminate
  980. X *
  981. X * synopsis
  982. X *    char msg[];
  983. X *    flexfatal( msg );
  984. X */
  985. X
  986. Xvoid flexfatal( msg )
  987. Xchar msg[];
  988. X
  989. X    {
  990. X    fprintf( stderr, "%s: fatal internal error, %s\n", program_name, msg );
  991. X    flexend( 1 );
  992. X    }
  993. X
  994. X
  995. X/* flex_gettime - return current time
  996. X *
  997. X * synopsis
  998. X *    char *flex_gettime(), *time_str;
  999. X *    time_str = flex_gettime();
  1000. X *
  1001. X * note
  1002. X *    the routine name has the "flex_" prefix because of name clashes
  1003. X *    with Turbo-C
  1004. X */
  1005. X
  1006. X/* include sys/types.h to use time_t and make lint happy */
  1007. X
  1008. X#ifndef MS_DOS
  1009. X#ifndef VMS
  1010. X#include <sys/types.h>
  1011. X#else
  1012. X#include <types.h>
  1013. X#endif
  1014. X#endif
  1015. X
  1016. X#ifdef MS_DOS
  1017. X#include <time.h>
  1018. Xtypedef long time_t;
  1019. X#endif
  1020. X
  1021. Xchar *flex_gettime()
  1022. X
  1023. X    {
  1024. X    time_t t, time();
  1025. X    char *result, *ctime(), *copy_string();
  1026. X
  1027. X    t = time( (long *) 0 );
  1028. X
  1029. X    result = copy_string( ctime( &t ) );
  1030. X
  1031. X    /* get rid of trailing newline */
  1032. X    result[24] = '\0';
  1033. X
  1034. X    return ( result );
  1035. X    }
  1036. X
  1037. X
  1038. X/* lerrif - report an error message formatted with one integer argument
  1039. X *
  1040. X * synopsis
  1041. X *    char msg[];
  1042. X *    int arg;
  1043. X *    lerrif( msg, arg );
  1044. X */
  1045. X
  1046. Xvoid lerrif( msg, arg )
  1047. Xchar msg[];
  1048. Xint arg;
  1049. X
  1050. X    {
  1051. X    char errmsg[MAXLINE];
  1052. X    (void) sprintf( errmsg, msg, arg );
  1053. X    flexerror( errmsg );
  1054. X    }
  1055. X
  1056. X
  1057. X/* lerrsf - report an error message formatted with one string argument
  1058. X *
  1059. X * synopsis
  1060. X *    char msg[], arg[];
  1061. X *    lerrsf( msg, arg );
  1062. X */
  1063. X
  1064. Xvoid lerrsf( msg, arg )
  1065. Xchar msg[], arg[];
  1066. X
  1067. X    {
  1068. X    char errmsg[MAXLINE];
  1069. X
  1070. X    (void) sprintf( errmsg, msg, arg );
  1071. X    flexerror( errmsg );
  1072. X    }
  1073. X
  1074. X
  1075. X/* htoi - convert a hexadecimal digit string to an integer value
  1076. X *
  1077. X * synopsis:
  1078. X *    int val, htoi();
  1079. X *    Char str[];
  1080. X *    val = htoi( str );
  1081. X */
  1082. X
  1083. Xint htoi( str )
  1084. XChar str[];
  1085. X
  1086. X    {
  1087. X    int result;
  1088. X
  1089. X    (void) sscanf( (char *) str, "%x", &result );
  1090. X
  1091. X    return ( result );
  1092. X    }
  1093. X
  1094. X
  1095. X/* is_hex_digit - returns true if a character is a valid hex digit, false
  1096. X *          otherwise
  1097. X *
  1098. X * synopsis:
  1099. X *    int true_or_false, is_hex_digit();
  1100. X *    int ch;
  1101. X *    val = is_hex_digit( ch );
  1102. X */
  1103. X
  1104. Xint is_hex_digit( ch )
  1105. Xint ch;
  1106. X
  1107. X    {
  1108. X    if ( isdigit( ch ) )
  1109. X    return ( 1 );
  1110. X
  1111. X    switch ( clower( ch ) )
  1112. X    {
  1113. X    case 'a':
  1114. X    case 'b':
  1115. X    case 'c':
  1116. X    case 'd':
  1117. X    case 'e':
  1118. X    case 'f':
  1119. X        return ( 1 );
  1120. X
  1121. X    default:
  1122. X        return ( 0 );
  1123. X    }
  1124. X    }
  1125. X
  1126. X
  1127. X/* line_directive_out - spit out a "# line" statement */
  1128. X
  1129. Xvoid line_directive_out( output_file_name )
  1130. XFILE *output_file_name;
  1131. X
  1132. X    {
  1133. X    if ( infilename && gen_line_dirs )
  1134. X        fprintf( output_file_name, "# line %d \"%s\"\n", linenum, infilename );
  1135. X    }
  1136. X
  1137. X
  1138. X/* mk2data - generate a data statement for a two-dimensional array
  1139. X *
  1140. X * synopsis
  1141. X *    int value;
  1142. X *    mk2data( value );
  1143. X *
  1144. X *  generates a data statement initializing the current 2-D array to "value"
  1145. X */
  1146. Xvoid mk2data( value )
  1147. Xint value;
  1148. X
  1149. X    {
  1150. X    if ( datapos >= NUMDATAITEMS )
  1151. X    {
  1152. X    putchar( ',' );
  1153. X    dataflush();
  1154. X    }
  1155. X
  1156. X    if ( datapos == 0 )
  1157. X    /* indent */
  1158. X    fputs( "    ", stdout );
  1159. X
  1160. X    else
  1161. X    putchar( ',' );
  1162. X
  1163. X    ++datapos;
  1164. X
  1165. X    printf( "%5d", value );
  1166. X    }
  1167. X
  1168. X
  1169. X/* mkdata - generate a data statement
  1170. X *
  1171. X * synopsis
  1172. X *    int value;
  1173. X *    mkdata( value );
  1174. X *
  1175. X *  generates a data statement initializing the current array element to
  1176. X *  "value"
  1177. X */
  1178. Xvoid mkdata( value )
  1179. Xint value;
  1180. X
  1181. X    {
  1182. X    if ( datapos >= NUMDATAITEMS )
  1183. X    {
  1184. X    putchar( ',' );
  1185. X    dataflush();
  1186. X    }
  1187. X
  1188. X    if ( datapos == 0 )
  1189. X    /* indent */
  1190. X    fputs( "    ", stdout );
  1191. X
  1192. X    else
  1193. X    putchar( ',' );
  1194. X
  1195. X    ++datapos;
  1196. X
  1197. X    printf( "%5d", value );
  1198. X    }
  1199. X
  1200. X
  1201. X/* myctoi - return the integer represented by a string of digits
  1202. X *
  1203. X * synopsis
  1204. X *    Char array[];
  1205. X *    int val, myctoi();
  1206. X *    val = myctoi( array );
  1207. X *
  1208. X */
  1209. X
  1210. Xint myctoi( array )
  1211. XChar array[];
  1212. X
  1213. X    {
  1214. X    int val = 0;
  1215. X
  1216. X    (void) sscanf( (char *) array, "%d", &val );
  1217. X
  1218. X    return ( val );
  1219. X    }
  1220. X
  1221. X
  1222. X/* myesc - return character corresponding to escape sequence
  1223. X *
  1224. X * synopsis
  1225. X *    Char array[], c, myesc();
  1226. X *    c = myesc( array );
  1227. X *
  1228. X */
  1229. X
  1230. XChar myesc( array )
  1231. XChar array[];
  1232. X
  1233. X    {
  1234. X    Char c, esc_char;
  1235. X    register int sptr;
  1236. X
  1237. X    switch ( array[1] )
  1238. X    {
  1239. X    case 'a': return ( '\a' );
  1240. X    case 'b': return ( '\b' );
  1241. X    case 'f': return ( '\f' );
  1242. X    case 'n': return ( '\n' );
  1243. X    case 'r': return ( '\r' );
  1244. X    case 't': return ( '\t' );
  1245. X    case 'v': return ( '\v' );
  1246. X
  1247. X    case '0':
  1248. X    case '1':
  1249. X    case '2':
  1250. X    case '3':
  1251. X    case '4':
  1252. X    case '5':
  1253. X    case '6':
  1254. X    case '7':
  1255. X    case '8':
  1256. X    case '9':
  1257. X        { /* \<octal> */
  1258. X        sptr = 1;
  1259. X
  1260. X        while ( isascii( array[sptr] ) && isdigit( array[sptr] ) )
  1261. X        /* don't increment inside loop control because if
  1262. X         * isdigit() is a macro it might expand into multiple
  1263. X         * increments ...
  1264. X         */
  1265. X        ++sptr;
  1266. X
  1267. X        c = array[sptr];
  1268. X        array[sptr] = '\0';
  1269. X
  1270. X        esc_char = otoi( array + 1 );
  1271. X
  1272. X        array[sptr] = c;
  1273. X
  1274. X        return ( esc_char );
  1275. X        }
  1276. X
  1277. X    case 'x':
  1278. X        { /* \x<hex> */
  1279. X        int sptr = 2;
  1280. X
  1281. X        while ( isascii( array[sptr] ) && is_hex_digit( array[sptr] ) )
  1282. X        /* don't increment inside loop control because if
  1283. X         * isdigit() is a macro it might expand into multiple
  1284. X         * increments ...
  1285. X         */
  1286. X        ++sptr;
  1287. X
  1288. X        c = array[sptr];
  1289. X        array[sptr] = '\0';
  1290. X
  1291. X        esc_char = htoi( array + 2 );
  1292. X
  1293. X        array[sptr] = c;
  1294. X
  1295. X        return ( esc_char );
  1296. X        }
  1297. X
  1298. X    default:
  1299. X        return ( array[1] );
  1300. X    }
  1301. X    }
  1302. X
  1303. X
  1304. X/* otoi - convert an octal digit string to an integer value
  1305. X *
  1306. X * synopsis:
  1307. X *    int val, otoi();
  1308. X *    Char str[];
  1309. X *    val = otoi( str );
  1310. X */
  1311. X
  1312. Xint otoi( str )
  1313. XChar str[];
  1314. X
  1315. X    {
  1316. X    int result;
  1317. X
  1318. X    (void) sscanf( (char *) str, "%o", &result );
  1319. X
  1320. X    return ( result );
  1321. X    }
  1322. X
  1323. X
  1324. X/* readable_form - return the the human-readable form of a character
  1325. X *
  1326. X * synopsis:
  1327. X *    int c;
  1328. X *    char *readable_form();
  1329. X *    <string> = readable_form( c );
  1330. X *
  1331. X * The returned string is in static storage.
  1332. X */
  1333. X
  1334. Xchar *readable_form( c )
  1335. Xregister int c;
  1336. X
  1337. X    {
  1338. X    static char rform[10];
  1339. X
  1340. X    if ( (c >= 0 && c < 32) || c >= 127 )
  1341. X    {
  1342. X    switch ( c )
  1343. X        {
  1344. X        case '\n': return ( "\\n" );
  1345. X        case '\t': return ( "\\t" );
  1346. X        case '\f': return ( "\\f" );
  1347. X        case '\r': return ( "\\r" );
  1348. X        case '\b': return ( "\\b" );
  1349. X
  1350. X        default:
  1351. X        (void) sprintf( rform, "\\%.3o", c );
  1352. X        return ( rform );
  1353. X        }
  1354. X    }
  1355. X
  1356. X    else if ( c == ' ' )
  1357. X    return ( "' '" );
  1358. X
  1359. X    else
  1360. X    {
  1361. X    rform[0] = c;
  1362. X    rform[1] = '\0';
  1363. X
  1364. X    return ( rform );
  1365. X    }
  1366. X    }
  1367. X
  1368. X
  1369. X/* reallocate_array - increase the size of a dynamic array */
  1370. X
  1371. Xvoid *reallocate_array( array, size, element_size )
  1372. Xvoid *array;
  1373. Xint size, element_size;
  1374. X
  1375. X    {
  1376. X    register void *new_array;
  1377. X
  1378. X    /* same worry as in allocate_array(): */
  1379. X    if ( size * element_size <= 0 )
  1380. X        flexfatal( "attempt to increase array size by less than 1 byte" );
  1381. X
  1382. X    new_array =
  1383. X    (void *) realloc( (char *)array, (unsigned) (size * element_size ));
  1384. X
  1385. X    if ( new_array == NULL )
  1386. X    flexfatal( "attempt to increase array size failed" );
  1387. X
  1388. X    return ( new_array );
  1389. X    }
  1390. X
  1391. X
  1392. X/* skelout - write out one section of the skeleton file
  1393. X *
  1394. X * synopsis
  1395. X *    skelout();
  1396. X *
  1397. X * DESCRIPTION
  1398. X *    Copies from skelfile to stdout until a line beginning with "%%" or
  1399. X *    EOF is found.
  1400. X */
  1401. Xvoid skelout()
  1402. X
  1403. X    {
  1404. X    char buf[MAXLINE];
  1405. X
  1406. X    while ( fgets( buf, MAXLINE, skelfile ) != NULL )
  1407. X    if ( buf[0] == '%' && buf[1] == '%' )
  1408. X        break;
  1409. X    else
  1410. X        fputs( buf, stdout );
  1411. X    }
  1412. X
  1413. X
  1414. X/* transition_struct_out - output a yy_trans_info structure
  1415. X *
  1416. X * synopsis
  1417. X *     int element_v, element_n;
  1418. X *     transition_struct_out( element_v, element_n );
  1419. X *
  1420. X * outputs the yy_trans_info structure with the two elements, element_v and
  1421. X * element_n.  Formats the output with spaces and carriage returns.
  1422. X */
  1423. X
  1424. Xvoid transition_struct_out( element_v, element_n )
  1425. Xint element_v, element_n;
  1426. X
  1427. X    {
  1428. X    printf( "%7d, %5d,", element_v, element_n );
  1429. X
  1430. X    datapos += TRANS_STRUCT_PRINT_LENGTH;
  1431. X
  1432. X    if ( datapos >= 75 )
  1433. X    {
  1434. X    putchar( '\n' );
  1435. X
  1436. X    if ( ++dataline % 10 == 0 )
  1437. X        putchar( '\n' );
  1438. X
  1439. X    datapos = 0;
  1440. X    }
  1441. X    }
  1442. END_OF_FILE
  1443.   if test 14912 -ne `wc -c <'misc.c'`; then
  1444.     echo shar: \"'misc.c'\" unpacked with wrong size!
  1445.   fi
  1446.   # end of 'misc.c'
  1447. fi
  1448. if test -f 'nfa.c' -a "${1}" != "-c" ; then 
  1449.   echo shar: Will not clobber existing file \"'nfa.c'\"
  1450. else
  1451.   echo shar: Extracting \"'nfa.c'\" \(17603 characters\)
  1452.   sed "s/^X//" >'nfa.c' <<'END_OF_FILE'
  1453. X/* nfa - NFA construction routines */
  1454. X
  1455. X/*-
  1456. X * Copyright (c) 1990 The Regents of the University of California.
  1457. X * All rights reserved.
  1458. X *
  1459. X * This code is derived from software contributed to Berkeley by
  1460. X * Vern Paxson.
  1461. X * 
  1462. X * The United States Government has rights in this work pursuant
  1463. X * to contract no. DE-AC03-76SF00098 between the United States
  1464. X * Department of Energy and the University of California.
  1465. X *
  1466. X * Redistribution and use in source and binary forms are permitted provided
  1467. X * that: (1) source distributions retain this entire copyright notice and
  1468. X * comment, and (2) distributions including binaries display the following
  1469. X * acknowledgement:  ``This product includes software developed by the
  1470. X * University of California, Berkeley and its contributors'' in the
  1471. X * documentation or other materials provided with the distribution and in
  1472. X * all advertising materials mentioning features or use of this software.
  1473. X * Neither the name of the University nor the names of its contributors may
  1474. X * be used to endorse or promote products derived from this software without
  1475. X * specific prior written permission.
  1476. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  1477. X * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  1478. X * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  1479. X */
  1480. X
  1481. X#ifndef lint
  1482. Xstatic char rcsid[] =
  1483. X    "@(#) $Header: /usr/fsys/odin/a/vern/flex/RCS/nfa.c,v 2.6 90/06/27 23:48:29 vern Exp $ (LBL)";
  1484. X#endif
  1485. X
  1486. X#include "flexdef.h"
  1487. X
  1488. X
  1489. X/* declare functions that have forward references */
  1490. X
  1491. Xint dupmachine PROTO((int));
  1492. Xvoid mkxtion PROTO((int, int));
  1493. X
  1494. X
  1495. X/* add_accept - add an accepting state to a machine
  1496. X *
  1497. X * synopsis
  1498. X *
  1499. X *   add_accept( mach, accepting_number );
  1500. X *
  1501. X * accepting_number becomes mach's accepting number.
  1502. X */
  1503. X
  1504. Xvoid add_accept( mach, accepting_number )
  1505. Xint mach, accepting_number;
  1506. X
  1507. X    {
  1508. X    /* hang the accepting number off an epsilon state.  if it is associated
  1509. X     * with a state that has a non-epsilon out-transition, then the state
  1510. X     * will accept BEFORE it makes that transition, i.e., one character
  1511. X     * too soon
  1512. X     */
  1513. X
  1514. X    if ( transchar[finalst[mach]] == SYM_EPSILON )
  1515. X    accptnum[finalst[mach]] = accepting_number;
  1516. X
  1517. X    else
  1518. X    {
  1519. X    int astate = mkstate( SYM_EPSILON );
  1520. X    accptnum[astate] = accepting_number;
  1521. X    mach = link_machines( mach, astate );
  1522. X    }
  1523. X    }
  1524. X
  1525. X
  1526. X/* copysingl - make a given number of copies of a singleton machine
  1527. X *
  1528. X * synopsis
  1529. X *
  1530. X *   newsng = copysingl( singl, num );
  1531. X *
  1532. X *     newsng - a new singleton composed of num copies of singl
  1533. X *     singl  - a singleton machine
  1534. X *     num    - the number of copies of singl to be present in newsng
  1535. X */
  1536. X
  1537. Xint copysingl( singl, num )
  1538. Xint singl, num;
  1539. X
  1540. X    {
  1541. X    int copy, i;
  1542. X
  1543. X    copy = mkstate( SYM_EPSILON );
  1544. X
  1545. X    for ( i = 1; i <= num; ++i )
  1546. X    copy = link_machines( copy, dupmachine( singl ) );
  1547. X
  1548. X    return ( copy );
  1549. X    }
  1550. X
  1551. X
  1552. X/* dumpnfa - debugging routine to write out an nfa
  1553. X *
  1554. X * synopsis
  1555. X *    int state1;
  1556. X *    dumpnfa( state1 );
  1557. X */
  1558. X
  1559. Xvoid dumpnfa( state1 )
  1560. Xint state1;
  1561. X
  1562. X    {
  1563. X    int sym, tsp1, tsp2, anum, ns;
  1564. X
  1565. X    fprintf( stderr, "\n\n********** beginning dump of nfa with start state %d\n",
  1566. X         state1 );
  1567. X
  1568. X    /* we probably should loop starting at firstst[state1] and going to
  1569. X     * lastst[state1], but they're not maintained properly when we "or"
  1570. X     * all of the rules together.  So we use our knowledge that the machine
  1571. X     * starts at state 1 and ends at lastnfa.
  1572. X     */
  1573. X
  1574. X    /* for ( ns = firstst[state1]; ns <= lastst[state1]; ++ns ) */
  1575. X    for ( ns = 1; ns <= lastnfa; ++ns )
  1576. X    {
  1577. X    fprintf( stderr, "state # %4d\t", ns );
  1578. X
  1579. X    sym = transchar[ns];
  1580. X    tsp1 = trans1[ns];
  1581. X    tsp2 = trans2[ns];
  1582. X    anum = accptnum[ns];
  1583. X
  1584. X    fprintf( stderr, "%3d:  %4d, %4d", sym, tsp1, tsp2 );
  1585. X
  1586. X    if ( anum != NIL )
  1587. X        fprintf( stderr, "  [%d]", anum );
  1588. X
  1589. X    fprintf( stderr, "\n" );
  1590. X    }
  1591. X
  1592. X    fprintf( stderr, "********** end of dump\n" );
  1593. X    }
  1594. X
  1595. X
  1596. X/* dupmachine - make a duplicate of a given machine
  1597. X *
  1598. X * synopsis
  1599. X *
  1600. X *   copy = dupmachine( mach );
  1601. X *
  1602. X *     copy - holds duplicate of mach
  1603. X *     mach - machine to be duplicated
  1604. X *
  1605. X * note that the copy of mach is NOT an exact duplicate; rather, all the
  1606. X * transition states values are adjusted so that the copy is self-contained,
  1607. X * as the original should have been.
  1608. X *
  1609. X * also note that the original MUST be contiguous, with its low and high
  1610. X * states accessible by the arrays firstst and lastst
  1611. X */
  1612. X
  1613. Xint dupmachine( mach )
  1614. Xint mach;
  1615. X
  1616. X    {
  1617. X    int i, init, state_offset;
  1618. X    int state = 0;
  1619. X    int last = lastst[mach];
  1620. X
  1621. X    for ( i = firstst[mach]; i <= last; ++i )
  1622. X    {
  1623. X    state = mkstate( transchar[i] );
  1624. X
  1625. X    if ( trans1[i] != NO_TRANSITION )
  1626. X        {
  1627. X        mkxtion( finalst[state], trans1[i] + state - i );
  1628. X
  1629. X        if ( transchar[i] == SYM_EPSILON && trans2[i] != NO_TRANSITION )
  1630. X        mkxtion( finalst[state], trans2[i] + state - i );
  1631. X        }
  1632. X
  1633. X    accptnum[state] = accptnum[i];
  1634. X    }
  1635. X
  1636. X    if ( state == 0 )
  1637. X    flexfatal( "empty machine in dupmachine()" );
  1638. X
  1639. X    state_offset = state - i + 1;
  1640. X
  1641. X    init = mach + state_offset;
  1642. X    firstst[init] = firstst[mach] + state_offset;
  1643. X    finalst[init] = finalst[mach] + state_offset;
  1644. X    lastst[init] = lastst[mach] + state_offset;
  1645. X
  1646. X    return ( init );
  1647. X    }
  1648. X
  1649. X
  1650. X/* finish_rule - finish up the processing for a rule
  1651. X *
  1652. X * synopsis
  1653. X *
  1654. X *   finish_rule( mach, variable_trail_rule, headcnt, trailcnt );
  1655. X *
  1656. X * An accepting number is added to the given machine.  If variable_trail_rule
  1657. X * is true then the rule has trailing context and both the head and trail
  1658. X * are variable size.  Otherwise if headcnt or trailcnt is non-zero then
  1659. X * the machine recognizes a pattern with trailing context and headcnt is
  1660. X * the number of characters in the matched part of the pattern, or zero
  1661. X * if the matched part has variable length.  trailcnt is the number of
  1662. X * trailing context characters in the pattern, or zero if the trailing
  1663. X * context has variable length.
  1664. X */
  1665. X
  1666. Xvoid finish_rule( mach, variable_trail_rule, headcnt, trailcnt )
  1667. Xint mach, variable_trail_rule, headcnt, trailcnt;
  1668. X
  1669. X    {
  1670. X    add_accept( mach, num_rules );
  1671. X
  1672. X    /* we did this in new_rule(), but it often gets the wrong
  1673. X     * number because we do it before we start parsing the current rule
  1674. X     */
  1675. X    rule_linenum[num_rules] = linenum;
  1676. X
  1677. X    /* if this is a continued action, then the line-number has
  1678. X     * already been updated, giving us the wrong number
  1679. X     */
  1680. X    if ( continued_action )
  1681. X    --rule_linenum[num_rules];
  1682. X
  1683. X    fprintf( temp_action_file, "case %d:\n", num_rules );
  1684. X
  1685. X    if ( variable_trail_rule )
  1686. X    {
  1687. X    rule_type[num_rules] = RULE_VARIABLE;
  1688. X
  1689. X    if ( performance_report )
  1690. X        fprintf( stderr, "Variable trailing context rule at line %d\n",
  1691. X             rule_linenum[num_rules] );
  1692. X
  1693. X    variable_trailing_context_rules = true;
  1694. X    }
  1695. X
  1696. X    else
  1697. X    {
  1698. X    rule_type[num_rules] = RULE_NORMAL;
  1699. X
  1700. X    if ( headcnt > 0 || trailcnt > 0 )
  1701. X        {
  1702. X        /* do trailing context magic to not match the trailing characters */
  1703. X        char *scanner_cp = "yy_c_buf_p = yy_cp";
  1704. X        char *scanner_bp = "yy_bp";
  1705. X
  1706. X        fprintf( temp_action_file,
  1707. X    "*yy_cp = yy_hold_char; /* undo effects of setting up yytext */\n" );
  1708. X
  1709. X        if ( headcnt > 0 )
  1710. X        fprintf( temp_action_file, "%s = %s + %d;\n",
  1711. X             scanner_cp, scanner_bp, headcnt );
  1712. X
  1713. X        else
  1714. X        fprintf( temp_action_file,
  1715. X             "%s -= %d;\n", scanner_cp, trailcnt );
  1716. X    
  1717. X        fprintf( temp_action_file,
  1718. X             "YY_DO_BEFORE_ACTION; /* set up yytext again */\n" );
  1719. X        }
  1720. X    }
  1721. X
  1722. X    line_directive_out( temp_action_file );
  1723. X    }
  1724. X
  1725. X
  1726. X/* link_machines - connect two machines together
  1727. X *
  1728. X * synopsis
  1729. X *
  1730. X *   new = link_machines( first, last );
  1731. X *
  1732. X *     new    - a machine constructed by connecting first to last
  1733. X *     first  - the machine whose successor is to be last
  1734. X *     last   - the machine whose predecessor is to be first
  1735. X *
  1736. X * note: this routine concatenates the machine first with the machine
  1737. X *  last to produce a machine new which will pattern-match first first
  1738. X *  and then last, and will fail if either of the sub-patterns fails.
  1739. X *  FIRST is set to new by the operation.  last is unmolested.
  1740. X */
  1741. X
  1742. Xint link_machines( first, last )
  1743. Xint first, last;
  1744. X
  1745. X    {
  1746. X    if ( first == NIL )
  1747. X    return ( last );
  1748. X
  1749. X    else if ( last == NIL )
  1750. X    return ( first );
  1751. X
  1752. X    else
  1753. X    {
  1754. X    mkxtion( finalst[first], last );
  1755. X    finalst[first] = finalst[last];
  1756. X    lastst[first] = max( lastst[first], lastst[last] );
  1757. X    firstst[first] = min( firstst[first], firstst[last] );
  1758. X
  1759. X    return ( first );
  1760. X    }
  1761. X    }
  1762. X
  1763. X
  1764. X/* mark_beginning_as_normal - mark each "beginning" state in a machine
  1765. X *                            as being a "normal" (i.e., not trailing context-
  1766. X *                            associated) states
  1767. X *
  1768. X * synopsis
  1769. X *
  1770. X *   mark_beginning_as_normal( mach )
  1771. X *
  1772. X *     mach - machine to mark
  1773. X *
  1774. X * The "beginning" states are the epsilon closure of the first state
  1775. X */
  1776. X
  1777. Xvoid mark_beginning_as_normal( mach )
  1778. Xregister int mach;
  1779. X
  1780. X    {
  1781. X    switch ( state_type[mach] )
  1782. X    {
  1783. X    case STATE_NORMAL:
  1784. X        /* oh, we've already visited here */
  1785. X        return;
  1786. X
  1787. X    case STATE_TRAILING_CONTEXT:
  1788. X        state_type[mach] = STATE_NORMAL;
  1789. X
  1790. X        if ( transchar[mach] == SYM_EPSILON )
  1791. X        {
  1792. X        if ( trans1[mach] != NO_TRANSITION )
  1793. X            mark_beginning_as_normal( trans1[mach] );
  1794. X
  1795. X        if ( trans2[mach] != NO_TRANSITION )
  1796. X            mark_beginning_as_normal( trans2[mach] );
  1797. X        }
  1798. X        break;
  1799. X
  1800. X    default:
  1801. X        flexerror( "bad state type in mark_beginning_as_normal()" );
  1802. X        break;
  1803. X    }
  1804. X    }
  1805. X
  1806. X
  1807. X/* mkbranch - make a machine that branches to two machines
  1808. X *
  1809. X * synopsis
  1810. X *
  1811. X *   branch = mkbranch( first, second );
  1812. X *
  1813. X *     branch - a machine which matches either first's pattern or second's
  1814. X *     first, second - machines whose patterns are to be or'ed (the | operator)
  1815. X *
  1816. X * note that first and second are NEITHER destroyed by the operation.  Also,
  1817. X * the resulting machine CANNOT be used with any other "mk" operation except
  1818. X * more mkbranch's.  Compare with mkor()
  1819. X */
  1820. X
  1821. Xint mkbranch( first, second )
  1822. Xint first, second;
  1823. X
  1824. X    {
  1825. X    int eps;
  1826. X
  1827. X    if ( first == NO_TRANSITION )
  1828. X    return ( second );
  1829. X
  1830. X    else if ( second == NO_TRANSITION )
  1831. X    return ( first );
  1832. X
  1833. X    eps = mkstate( SYM_EPSILON );
  1834. X
  1835. X    mkxtion( eps, first );
  1836. X    mkxtion( eps, second );
  1837. X
  1838. X    return ( eps );
  1839. X    }
  1840. X
  1841. X
  1842. X/* mkclos - convert a machine into a closure
  1843. X *
  1844. X * synopsis
  1845. X *   new = mkclos( state );
  1846. X *
  1847. X *     new - a new state which matches the closure of "state"
  1848. X */
  1849. X
  1850. Xint mkclos( state )
  1851. Xint state;
  1852. X
  1853. X    {
  1854. X    return ( mkopt( mkposcl( state ) ) );
  1855. X    }
  1856. X
  1857. X
  1858. X/* mkopt - make a machine optional
  1859. X *
  1860. X * synopsis
  1861. X *
  1862. X *   new = mkopt( mach );
  1863. X *
  1864. X *     new  - a machine which optionally matches whatever mach matched
  1865. X *     mach - the machine to make optional
  1866. X *
  1867. X * notes:
  1868. X *     1. mach must be the last machine created
  1869. X *     2. mach is destroyed by the call
  1870. X */
  1871. X
  1872. Xint mkopt( mach )
  1873. Xint mach;
  1874. X
  1875. X    {
  1876. X    int eps;
  1877. X
  1878. X    if ( ! SUPER_FREE_EPSILON(finalst[mach]) )
  1879. X    {
  1880. X    eps = mkstate( SYM_EPSILON );
  1881. X    mach = link_machines( mach, eps );
  1882. X    }
  1883. X
  1884. X    /* can't skimp on the following if FREE_EPSILON(mach) is true because
  1885. X     * some state interior to "mach" might point back to the beginning
  1886. X     * for a closure
  1887. X     */
  1888. X    eps = mkstate( SYM_EPSILON );
  1889. X    mach = link_machines( eps, mach );
  1890. X
  1891. X    mkxtion( mach, finalst[mach] );
  1892. X
  1893. X    return ( mach );
  1894. X    }
  1895. X
  1896. X
  1897. X/* mkor - make a machine that matches either one of two machines
  1898. X *
  1899. X * synopsis
  1900. X *
  1901. X *   new = mkor( first, second );
  1902. X *
  1903. X *     new - a machine which matches either first's pattern or second's
  1904. X *     first, second - machines whose patterns are to be or'ed (the | operator)
  1905. X *
  1906. X * note that first and second are both destroyed by the operation
  1907. X * the code is rather convoluted because an attempt is made to minimize
  1908. X * the number of epsilon states needed
  1909. X */
  1910. X
  1911. Xint mkor( first, second )
  1912. Xint first, second;
  1913. X
  1914. X    {
  1915. X    int eps, orend;
  1916. X
  1917. X    if ( first == NIL )
  1918. X    return ( second );
  1919. X
  1920. X    else if ( second == NIL )
  1921. X    return ( first );
  1922. X
  1923. X    else
  1924. X    {
  1925. X    /* see comment in mkopt() about why we can't use the first state
  1926. X     * of "first" or "second" if they satisfy "FREE_EPSILON"
  1927. X     */
  1928. X    eps = mkstate( SYM_EPSILON );
  1929. X
  1930. X    first = link_machines( eps, first );
  1931. X
  1932. X    mkxtion( first, second );
  1933. X
  1934. X    if ( SUPER_FREE_EPSILON(finalst[first]) &&
  1935. X         accptnum[finalst[first]] == NIL )
  1936. X        {
  1937. X        orend = finalst[first];
  1938. X        mkxtion( finalst[second], orend );
  1939. X        }
  1940. X
  1941. X    else if ( SUPER_FREE_EPSILON(finalst[second]) &&
  1942. X          accptnum[finalst[second]] == NIL )
  1943. X        {
  1944. X        orend = finalst[second];
  1945. X        mkxtion( finalst[first], orend );
  1946. X        }
  1947. X
  1948. X    else
  1949. X        {
  1950. X        eps = mkstate( SYM_EPSILON );
  1951. X
  1952. X        first = link_machines( first, eps );
  1953. X        orend = finalst[first];
  1954. X
  1955. X        mkxtion( finalst[second], orend );
  1956. X        }
  1957. X    }
  1958. X
  1959. X    finalst[first] = orend;
  1960. X    return ( first );
  1961. X    }
  1962. X
  1963. X
  1964. X/* mkposcl - convert a machine into a positive closure
  1965. X *
  1966. X * synopsis
  1967. X *   new = mkposcl( state );
  1968. X *
  1969. X *    new - a machine matching the positive closure of "state"
  1970. X */
  1971. X
  1972. Xint mkposcl( state )
  1973. Xint state;
  1974. X
  1975. X    {
  1976. X    int eps;
  1977. X
  1978. X    if ( SUPER_FREE_EPSILON(finalst[state]) )
  1979. X    {
  1980. X    mkxtion( finalst[state], state );
  1981. X    return ( state );
  1982. X    }
  1983. X
  1984. X    else
  1985. X    {
  1986. X    eps = mkstate( SYM_EPSILON );
  1987. X    mkxtion( eps, state );
  1988. X    return ( link_machines( state, eps ) );
  1989. X    }
  1990. X    }
  1991. X
  1992. X
  1993. X/* mkrep - make a replicated machine
  1994. X *
  1995. X * synopsis
  1996. X *   new = mkrep( mach, lb, ub );
  1997. X *
  1998. X *    new - a machine that matches whatever "mach" matched from "lb"
  1999. X *          number of times to "ub" number of times
  2000. X *
  2001. X * note
  2002. X *   if "ub" is INFINITY then "new" matches "lb" or more occurrences of "mach"
  2003. X */
  2004. X
  2005. Xint mkrep( mach, lb, ub )
  2006. Xint mach, lb, ub;
  2007. X
  2008. X    {
  2009. X    int base_mach, tail, copy, i;
  2010. X
  2011. X    base_mach = copysingl( mach, lb - 1 );
  2012. X
  2013. X    if ( ub == INFINITY )
  2014. X    {
  2015. X    copy = dupmachine( mach );
  2016. X    mach = link_machines( mach,
  2017. X                  link_machines( base_mach, mkclos( copy ) ) );
  2018. X    }
  2019. X
  2020. X    else
  2021. X    {
  2022. X    tail = mkstate( SYM_EPSILON );
  2023. X
  2024. X    for ( i = lb; i < ub; ++i )
  2025. X        {
  2026. X        copy = dupmachine( mach );
  2027. X        tail = mkopt( link_machines( copy, tail ) );
  2028. X        }
  2029. X
  2030. X    mach = link_machines( mach, link_machines( base_mach, tail ) );
  2031. X    }
  2032. X
  2033. X    return ( mach );
  2034. X    }
  2035. X
  2036. X
  2037. X/* mkstate - create a state with a transition on a given symbol
  2038. X *
  2039. X * synopsis
  2040. X *
  2041. X *   state = mkstate( sym );
  2042. X *
  2043. X *     state - a new state matching sym
  2044. X *     sym   - the symbol the new state is to have an out-transition on
  2045. X *
  2046. X * note that this routine makes new states in ascending order through the
  2047. X * state array (and increments LASTNFA accordingly).  The routine DUPMACHINE
  2048. X * relies on machines being made in ascending order and that they are
  2049. X * CONTIGUOUS.  Change it and you will have to rewrite DUPMACHINE (kludge
  2050. X * that it admittedly is)
  2051. X */
  2052. X
  2053. Xint mkstate( sym )
  2054. Xint sym;
  2055. X
  2056. X    {
  2057. X    if ( ++lastnfa >= current_mns )
  2058. X    {
  2059. X    if ( (current_mns += MNS_INCREMENT) >= MAXIMUM_MNS )
  2060. X        lerrif( "input rules are too complicated (>= %d NFA states)",
  2061. X            current_mns );
  2062. X    
  2063. X    ++num_reallocs;
  2064. X
  2065. X    firstst = reallocate_integer_array( firstst, current_mns );
  2066. X    lastst = reallocate_integer_array( lastst, current_mns );
  2067. X    finalst = reallocate_integer_array( finalst, current_mns );
  2068. X    transchar = reallocate_integer_array( transchar, current_mns );
  2069. X    trans1 = reallocate_integer_array( trans1, current_mns );
  2070. X    trans2 = reallocate_integer_array( trans2, current_mns );
  2071. X    accptnum = reallocate_integer_array( accptnum, current_mns );
  2072. X    assoc_rule = reallocate_integer_array( assoc_rule, current_mns );
  2073. X    state_type = reallocate_integer_array( state_type, current_mns );
  2074. X    }
  2075. X
  2076. X    firstst[lastnfa] = lastnfa;
  2077. X    finalst[lastnfa] = lastnfa;
  2078. X    lastst[lastnfa] = lastnfa;
  2079. X    transchar[lastnfa] = sym;
  2080. X    trans1[lastnfa] = NO_TRANSITION;
  2081. X    trans2[lastnfa] = NO_TRANSITION;
  2082. X    accptnum[lastnfa] = NIL;
  2083. X    assoc_rule[lastnfa] = num_rules;
  2084. X    state_type[lastnfa] = current_state_type;
  2085. X
  2086. X    /* fix up equivalence classes base on this transition.  Note that any
  2087. X     * character which has its own transition gets its own equivalence class.
  2088. X     * Thus only characters which are only in character classes have a chance
  2089. X     * at being in the same equivalence class.  E.g. "a|b" puts 'a' and 'b'
  2090. X     * into two different equivalence classes.  "[ab]" puts them in the same
  2091. X     * equivalence class (barring other differences elsewhere in the input).
  2092. X     */
  2093. X
  2094. X    if ( sym < 0 )
  2095. X    {
  2096. X    /* we don't have to update the equivalence classes since that was
  2097. X     * already done when the ccl was created for the first time
  2098. X     */
  2099. X    }
  2100. X
  2101. X    else if ( sym == SYM_EPSILON )
  2102. X    ++numeps;
  2103. X
  2104. X    else
  2105. X    {
  2106. X    if ( useecs )
  2107. X        /* map NUL's to csize */
  2108. X        mkechar( sym ? sym : csize, nextecm, ecgroup );
  2109. X    }
  2110. X
  2111. X    return ( lastnfa );
  2112. X    }
  2113. X
  2114. X
  2115. X/* mkxtion - make a transition from one state to another
  2116. X *
  2117. X * synopsis
  2118. X *
  2119. X *   mkxtion( statefrom, stateto );
  2120. X *
  2121. X *     statefrom - the state from which the transition is to be made
  2122. X *     stateto   - the state to which the transition is to be made
  2123. X */
  2124. X
  2125. Xvoid mkxtion( statefrom, stateto )
  2126. Xint statefrom, stateto;
  2127. X
  2128. X    {
  2129. X    if ( trans1[statefrom] == NO_TRANSITION )
  2130. X    trans1[statefrom] = stateto;
  2131. X
  2132. X    else if ( (transchar[statefrom] != SYM_EPSILON) ||
  2133. X          (trans2[statefrom] != NO_TRANSITION) )
  2134. X    flexfatal( "found too many transitions in mkxtion()" );
  2135. X
  2136. X    else
  2137. X    { /* second out-transition for an epsilon state */
  2138. X    ++eps2;
  2139. X    trans2[statefrom] = stateto;
  2140. X    }
  2141. X    }
  2142. X
  2143. X/* new_rule - initialize for a new rule
  2144. X *
  2145. X * synopsis
  2146. X *
  2147. X *   new_rule();
  2148. X *
  2149. X * the global num_rules is incremented and the any corresponding dynamic
  2150. X * arrays (such as rule_type[]) are grown as needed.
  2151. X */
  2152. X
  2153. Xvoid new_rule()
  2154. X
  2155. X    {
  2156. X    if ( ++num_rules >= current_max_rules )
  2157. X    {
  2158. X    ++num_reallocs;
  2159. X    current_max_rules += MAX_RULES_INCREMENT;
  2160. X    rule_type = reallocate_integer_array( rule_type, current_max_rules );
  2161. X    rule_linenum =
  2162. X        reallocate_integer_array( rule_linenum, current_max_rules );
  2163. X    }
  2164. X
  2165. X    if ( num_rules > MAX_RULE )
  2166. X    lerrif( "too many rules (> %d)!", MAX_RULE );
  2167. X
  2168. X    rule_linenum[num_rules] = linenum;
  2169. X    }
  2170. END_OF_FILE
  2171.   if test 17603 -ne `wc -c <'nfa.c'`; then
  2172.     echo shar: \"'nfa.c'\" unpacked with wrong size!
  2173.   fi
  2174.   # end of 'nfa.c'
  2175. fi
  2176. echo shar: End of archive 8 \(of 10\).
  2177. cp /dev/null ark8isdone
  2178. MISSING=""
  2179. for I in 1 2 3 4 5 6 7 8 9 10 ; do
  2180.     if test ! -f ark${I}isdone ; then
  2181.     MISSING="${MISSING} ${I}"
  2182.     fi
  2183. done
  2184. if test "${MISSING}" = "" ; then
  2185.     echo You have unpacked all 10 archives.
  2186.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2187. else
  2188.     echo You still must unpack the following archives:
  2189.     echo "        " ${MISSING}
  2190. fi
  2191. exit 0
  2192. exit 0 # Just in case...
  2193.